﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Asol.Reporting.Support;
using Asol.Reporting.Support.Data;

namespace Asol.Reporting.Support.Components
{
    #region class Grid : Grid, který zobrazuje data z paměťové tabulky Table
    /// <summary>
    /// Grid : Grid, který zobrazuje data z paměťové tabulky Table
    /// </summary>
    public class Grid : DataGridView
    {
        #region Konstrukce, instanční proměnné
        /// <summary>
        /// Konstruktor
        /// </summary>
        public Grid()
        {
            this.InitializeProperty();
        }
        private void InitializeProperty()
        {
            this.AllowDrop = false;
            this.AllowUserToOrderColumns = true;
            this.AllowUserToResizeColumns = true;
            this.AllowUserToResizeRows = false;
            this.AutoGenerateColumns = false;
            this.AutoSize = false;
            this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
            this.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
            this.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
            this.ColumnHeadersHeight = 45;
            this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
            this.ColumnHeadersVisible = true;
            this.EnableHeadersVisualStyles = true;
            this.MultiSelect = true;
            this.RowHeadersWidth = 23;
            this.ScrollBars = System.Windows.Forms.ScrollBars.Both;
            this.ShowEditingIcon = false;
            this.StandardTab = false;

            this.DoubleBuffered = true;

            this.DefaultCellStyle = new DataGridViewCellStyle();
            this.DefaultCellStyle.SelectionBackColor = Color.BlueViolet;
            this.DefaultCellStyle.SelectionForeColor = Color.Wheat;
            this.DefaultCellStyle.NullValue = "";
            this.DefaultCellStyle.ForeColor = Color.Black;
            this.DefaultCellStyle.BackColor = Color.Wheat;

            this.DataError += new DataGridViewDataErrorEventHandler(_Grid_DataError);
        }
        void _Grid_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            // ignorovat
        }
        private GridEditMode _EditMode;
        private Table _DataTable;
        #endregion
        #region Public property, eventy a metody
        /// <summary>
        /// Režim editace
        /// </summary>
        public GridEditMode SimpleEditMode
        {
            get { return this._EditMode; }
            set
            {
                this._EditMode = value;
                this._AcceptEditMode();
            }
        }
        /// <summary>
        /// Tabulka, jejíž data jsou zobrazena.
        /// Po vložení nového objektu dojde k reloadu jeho dat do tabulky.
        /// Property je autoinicializační: pokud bude uživatel číst hodnotu, a dosud nebude tabulka vytvořena, vytvoří se nová.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Table DataTable
        {
            get
            {
                if (this._DataTable == null)
                    this._DataTable = Table.Empty;
                return this._DataTable;
            }
            set
            {
                this._DataTable = value;
                if (value != null)
                    value.Grid = this;
                this._ReloadContent();
            }
        }
        /// <summary>
        /// Obsahuje aktuálně vybrané řádky, typované na zdejší typ řádků (GridRow).
        /// Pozor: řádky musejí být vybrané jako celek (za svoje záhlaví) = nestačí jedna buňka.
        /// Jinou možnost nabízí property SelectedSimpleGridRowsFromCell.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IEnumerable<GridRow> SelectedSimpleGridWholeRows
        {
            get
            {
                List<GridRow> result = new List<GridRow>();

                foreach (DataGridViewRow row in this.SelectedRows)
                {
                    GridRow dgRow = row as GridRow;
                    if (dgRow != null)
                        result.Add(dgRow);
                }
                return result;
            }
        }
        /// <summary>
        /// Obsahuje aktuálně vybrané řádky, typované na zdejší typ řádků (GridRow).
        /// Pozor: řádek do tohoto výběru se dostane tak, že je vybraná jakákoli jeho buňka (Cell), nemusí být vybrán řádek jako celek (za svoje záhlaví).
        /// Jinou možnost nabízí property SelectedSimpleGridWholeRows.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IEnumerable<GridRow> SelectedSimpleGridRowsFromCell
        {
            get
            {
                Dictionary<int, GridRow> result = new Dictionary<int, GridRow>();

                foreach (DataGridViewCell cell in this.SelectedCells)
                {
                    if (!result.ContainsKey(cell.RowIndex))
                    {
                        GridRow dgRow = cell.OwningRow as GridRow;
                        if (dgRow != null)
                            result.Add(cell.RowIndex, dgRow);
                    }
                }
                return result.Values.ToList();
            }
        }
        /// <summary>
        /// Obsahuje aktuálně vybrané řádky, typované na datový typ řádků (Data.Row).
        /// Pozor: řádek do tohoto výběru se dostane tak, že je vybraná jakákoli jeho buňka (Cell), nemusí být vybrán řádek jako celek (za svoje záhlaví).
        /// Jinou možnost nabízí property SelectedSimpleGridWholeRows.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IEnumerable<Data.Row> SelectedDataRowsFromCell
        {
            get
            {
                Dictionary<int, Data.Row> result = new Dictionary<int, Data.Row>();

                foreach (DataGridViewCell cell in this.SelectedCells)
                {
                    if (!result.ContainsKey(cell.RowIndex))
                    {
                        GridRow dgRow = cell.OwningRow as GridRow;
                        if (dgRow != null)
                            result.Add(cell.RowIndex, dgRow.DataRow);
                    }
                }
                return result.Values.ToList();
            }
        }
        /// <summary>
        /// Událost volaná před změnou hodnoty. Změnu lze odvolat, lze modifikovat ukládanou hodnotu.
        /// </summary>
        public event TableValueChangingHandler ValueChanging;
        /// <summary>
        /// Událost volaná po změně hodnoty. Změnu již nelze odvolat.
        /// </summary>
        public event TableValueChangeHandler ValueChanged;
        /// <summary>
        /// Vyvolá událost ValueChanging.
        /// Proběhne těsně před vložením nové hodnoty do tabulky.
        /// Handler může hodnotu změnit nebo může změnu odmítnout.
        /// </summary>
        internal void OnValueChanging(object sender, TableValueChangingArgs args)
        {
            if (this.ValueChanging != null)
                this.ValueChanging(sender, args);
        }
        /// <summary>
        /// Vyvolá událost ValueChanged.
        /// Proběhne až poté, kdy je do tabulky vložena nová hodnota.
        /// </summary>
        internal void OnValueChange(Data.Row sender, TableValueChangeArgs args)
        {
            if (this.ValueChanged != null)
                this.ValueChanged(sender, args);
        }
        /// <summary>
        /// Metoda smaže kompletně celou tabulku (sloupce + řádky).
        /// </summary>
        public void Clear()
        {
            if (this._DataTable != null)
            {
                this._DataTable.Rows.Clear();
                this._DataTable.Columns.Clear();
            }
        }
        /// <summary>
        /// Metoda smaže pouze řádky, nechá sloupce.
        /// </summary>
        public void ClearRows()
        {
            if (this._DataTable != null)
                this._DataTable.Rows.Clear();
        }
        #endregion
        #region Load data from Table, Get & Set value from/to Table
        /// <summary>
        /// Smaže celý obsah tabulky, jen vizuální prvky (řádky + sloupce)
        /// </summary>
        private void _ClearData()
        {
            this.Rows.Clear();
            this.Columns.Clear();
        }
        private void _ReloadContent()
        {
            this._ClearData();

            Table table = this._DataTable;
            if (table == null) return;
            if (table.ColumnCount == 0) return;

            this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;      // Výrazný vliv: 2000 => 510 milisec
            this.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;            // Téměř bez vlivu: 2000 => 1850
            this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;  // Výrazný vliv: 510 => 35
            this.EnableHeadersVisualStyles = true;                                                      // Bez vlivu na rychlost
            this.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing;          // Minimální vliv na rychlost

            // Pokud se sloupce a řádky vkládají s nastavením různých property na Autosize, 
            //  pak se výrazně prodlužuje čas načítání (téměř na desetinásobek !!!)
            this._LoadColumns(table.Columns);        // 1000 milisec / 137 columns
            this._LoadRows(table.Rows);              // dalších 1000 milisec / 750 řádků × 137 columns, z toho 860 milisec = vložení řádku do Rows

            //this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;           // Aplikace po vložení všech 450 řádků: 110 => 199 milisec
            //this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; // 199 => 205 milisec
        }
        /// <summary>
        /// Načte sloupce z DataTable (dodané jako parametr) do gridu
        /// </summary>
        /// <param name="columns"></param>
        private void _LoadColumns(Data.ColumnCollection columns)
        {
            foreach (Data.Column column in columns)
            {
                GridColumn dgCol = new GridColumn(column);
                dgCol.Name = column.ColumnName;
                dgCol.DefaultCellStyle = this.DefaultCellStyle.Clone();
                dgCol.FillPropertyFromData(column, null);
                this.Columns.Add(dgCol);
            }
        }
        /// <summary>
        /// Načte řádky z DataTable (dodané jako parametr) do gridu
        /// </summary>
        /// <param name="rows"></param>
        private void _LoadRows(Data.RowCollection rows)
        {
            foreach (Data.Row row in rows)
                this._AddRow(row);
        }
        /// <summary>
        /// Metoda smaže všechny vizuální sloupce.
        /// Volá se interně, z datové tabulky. Pokud by se volala přímo, pak by se smazaly jen vizuální sloupce, ale datové by zůstaly.
        /// </summary>
        public void ClearColumnsInternal()
        {
            this.Columns.Clear();
        }
        /// <summary>
        /// Přidá do gridu řádek.
        /// Řádek nepřidává do dat, tam odsud právě přichází tento požadavek na přidání datového řádku do vizuální vrstvy.
        /// </summary>
        /// <param name="row"></param>
        public void AddDataRowInternal(Data.Row row)
        {
            int currentColumn = this.CurrentCellAddress.X;
            if (currentColumn < 0)
            {
                DataGridViewColumn column = this.Columns.GetFirstColumn(DataGridViewElementStates.Visible);
                if (column != null)
                    currentColumn = column.Index;
            }
            GridRow dgRow = this._AddRow(row);
            int rowIndex = this.Rows.Count - 1;
            this.SetCurrentCellAddressCore(currentColumn, rowIndex, false, false, false);
            this.FirstDisplayedScrollingRowIndex = rowIndex;
        }
        /// <summary>
        /// Přidá do gridu řádek, neřeší nic víc.
        /// </summary>
        /// <param name="row"></param>
        private GridRow _AddRow(Data.Row row)
        {
            GridRow dgRow = new GridRow(row);
            foreach (var col in this.Columns)
            {
                GridColumn column = col as GridColumn;
                DataGridViewCell cell = null;
                CellType cellType = (column == null ? CellType.TextBox : column.DataColumn.GridCellType);
                switch (cellType)
                {
                    case CellType.ComboBox:
                        cell = new GridCellCombo();
                        break;
                    case CellType.Image:
                    case CellType.TextBox:
                    default:
                        cell = new GridCellText();
                        break;
                }
                dgRow.Cells.Add(cell);
            }

            this.Rows.Add(dgRow);
            return dgRow;
        }
        /// <summary>
        /// Odebere z gridu všechny GridRow, které v sobě obsahují referenci na daný datový řádek.
        /// Řádek neodebírá z dat, tam odsud právě přichází tento požadavek na odebrání datového řádku z vizuální vrstvy.
        /// </summary>
        /// <param name="row"></param>
        public void RemoveDataRowInternal(Data.Row row)
        {
            int startIndex = 0;
            while (true)
            {
                int index = -1;
                for (int i = startIndex; i < this.Rows.Count; i++)
                {
                    GridRow dgRow = this.Rows[i] as GridRow;
                    if (dgRow != null && Object.ReferenceEquals(dgRow.DataRow, row))
                    {
                        index = i;
                        break;
                    }
                }
                if (index < 0) break;

                this.Rows.RemoveAt(index);
                startIndex = index;
            }
        }
        /// <summary>
        /// Smaže všechny řádky.
        /// Řádky nemaže z dat, tam odsud právě přichází tento požadavek na smazání řádků do vizuální vrstvy.
        /// </summary>
        public void ClearRowsInternal()
        {
            this.Rows.Clear();
        }

        /// <summary>
        /// Přečte z datové tabulky hodnotu pro danou buňku.
        /// Vrací hodnotu neformátovanou, tak jak je v tabulce.
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public static string ReadFormattedValue(DataGridViewCell cell)
        {
            ValueData value = ReadValue(cell);
            if (value.IsEmpty) return "";
            FormatStyle formatStyle = GetFormatStyle(cell);
            return formatStyle.ConvertValueToText(value);
        }
        /// <summary>
        /// Hodnotu z dané buňky (vizuálně formátovanou) převede do hodnoty datové a uloží do datové tabulky.
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public static bool StoreFormattedValue(DataGridViewCell cell)
        {
            return StoreFormattedValue(cell, cell.Value);
        }
        /// <summary>
        /// Hodnotu z dané buňky (explicitně dodanou, vizuálně formátovanou) převede do hodnoty datové a uloží do datové tabulky.
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static bool StoreFormattedValue(DataGridViewCell cell, object text)
        {
            GridColumn column = cell.OwningColumn as GridColumn;
            if (column == null || column.DataColumn == null) return false;
            FormatStyle formatStyle = GetFormatStyle(cell);
            ValueData value = formatStyle.ConvertTextToValue(text, column.DataColumn.DataType);
            StoreValue(cell, value);
            return true;
        }
        /// <summary>
        /// Přečte z datové tabulky hodnotu pro danou buňku.
        /// Vrací hodnotu neformátovanou, tak jak je v tabulce.
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public static ValueData ReadValue(DataGridViewCell cell)
        {
            GridColumn column = cell.OwningColumn as GridColumn;
            GridRow row = cell.OwningRow as GridRow;
            Data.Row dataRow = (row == null || column == null ? null : row.DataRow);
            if (dataRow == null) return ValueData.Empty;
            RefreshToolTip(cell, row, column);
            return dataRow[column.Index];
        }
        /// <summary>
        /// Do datové tabulky uloží hodnotu pro danou buňku.
        /// Hodnotu nijak neupravuje.
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool StoreValue(DataGridViewCell cell, ValueData value)
        {
            GridColumn column = cell.OwningColumn as GridColumn;
            GridRow row = cell.OwningRow as GridRow;
            Data.Row dataRow = (row == null || column == null ? null : row.DataRow);
            if (dataRow == null) return false;
            dataRow[column.Index] = value;
            RefreshToolTip(cell, row, column);
            return true;
        }
        /// <summary>
        /// Aktualizuje ToolTip pro danou buňku
        /// </summary>
        /// <param name="cell"></param>
        public static void RefreshToolTip(DataGridViewCell cell)
        {
            GridRow row = cell.OwningRow as GridRow;
            GridColumn column = cell.OwningColumn as GridColumn;
            if (row == null || column == null) return;
            RefreshToolTip(cell, row, column);
        }
        /// <summary>
        /// Aktualizuje ToolTip pro danou buňku
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        public static void RefreshToolTip(DataGridViewCell cell, GridRow row, GridColumn column)
        {
            cell.ToolTipText = row.DataRow.GetCellTooltip(column.Index);
        }
        /// <summary>
        /// Vrátí objekt pro formátování hodnoty na text pro danou buňku.
        /// Nevrací null, situaci zachraňuje Assistant.DefaultFormatStyle.
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public static FormatStyle GetFormatStyle(DataGridViewCell cell)
        {
            GridRow row = cell.OwningRow as GridRow;
            GridColumn column = cell.OwningColumn as GridColumn;
            return GetFormatStyle(row, column);
        }
        /// <summary>
        /// Vrátí objekt pro formátování hodnoty na text pro buňku v daném řádku a sloupci
        /// </summary>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        public static FormatStyle GetFormatStyle(GridRow row, GridColumn column)
        {
            if (row == null || column == null) return null;
            return column.DataTable.GetFormatStyle(row.DataRow, column.DataColumn);
        }
        #endregion
        #region Set edit mode
        private void _AcceptEditMode()
        {
            GridEditMode editMode = this._EditMode;
            bool editContent = (editMode == GridEditMode.EditContent || editMode == GridEditMode.EditContentAndRows);
            bool editRows = (editMode == GridEditMode.EditContentAndRows);

            this.AllowUserToAddRows = editRows;
            this.AllowUserToDeleteRows = editRows;
            this.ReadOnly = !editContent;
        }
        #endregion
        #region Propojení Gridu a Table

        #region Notifikace o změnách z Table do Gridu = reakce Gridu na nová Data
        /// <summary>
        /// V tabulce se změnila hodnota určitého sloupce, v property Column.Grid*
        /// </summary>
        /// <param name="column"></param>
        /// <param name="changedProperties"></param>
        internal void NotifyGridColumnChange(Data.Column column, string changedProperties)
        {
            GridColumn dgCol = this.Columns[column.ColumnName] as GridColumn;
            if (dgCol != null)
                dgCol.FillPropertyFromData(column, changedProperties);
        }
        #endregion
        #endregion
    }
    #endregion
    #region class GridColumn : vizuální sloupec s daty
    /// <summary>
    /// GridColumn : vizuální sloupec s daty
    /// </summary>
    public class GridColumn : DataGridViewColumn
    {
        /// <summary>
        /// Bezparametrický konstruktor musí existovat, ale nesmí se používat.
        /// </summary>
        public GridColumn()
        {
            throw new DevException("Create a instance of class GridColumn without parameter (column) is not allowed.");
        }
        /// <summary>
        /// Konstruktor s převzetím reference na datový sloupec
        /// </summary>
        /// <param name="column"></param>
        public GridColumn(Data.Column column)
        {
            this._DataColumn = column;
        }
        /// <summary>
        /// Data načteného sloupce
        /// </summary>
        public Data.Column DataColumn { get { return this._DataColumn; } }
        private Data.Column _DataColumn;
        /// <summary>
        /// Data načtené tabulky
        /// </summary>
        public Data.Table DataTable { get { return (this._DataColumn == null ? null : this._DataColumn.Table); } }
        /// <summary>
        /// Z datové definice sloupce načte svoje vizuální parametry (column.GridHeaderText, atd).
        /// </summary>
        /// <param name="column"></param>
        /// <param name="changedProperties"></param>
        internal void FillPropertyFromData(Data.Column column, string changedProperties)
        {
            if (_IsChangedProperty(changedProperties, "GridHeaderText") && column.GridHeaderText != null)
                this.HeaderText = column.GridHeaderText;
            if (_IsChangedProperty(changedProperties, "GridColumnWidth") && column.GridColumnWidth.HasValue)
                this.Width = column.GridColumnWidth.Value;
            if (_IsChangedProperty(changedProperties, "GridFillWeight") && column.GridFillWeight.HasValue)
                this.FillWeight = column.GridFillWeight.Value;
            if (_IsChangedProperty(changedProperties, "GridAutoSizeMode") && column.GridAutoSizeMode != DataGridViewAutoSizeColumnMode.NotSet)
                this.AutoSizeMode = column.GridAutoSizeMode;
            if (_IsChangedProperty(changedProperties, "GridToolTipText") && column.GridToolTipText != null)
                this.ToolTipText = column.GridToolTipText;
            if (_IsChangedProperty(changedProperties, "GridVisible"))
                this.Visible = column.GridVisible;
        }
        /// <summary>
        /// Vrátí true, pokud změny (changed) jsou null = nevyjmenované, anebo pokud obsahují dané jméno property (name).
        /// </summary>
        /// <param name="changed"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        private static bool _IsChangedProperty(string changed, string name)
        {
            if (changed == null) return true;
            return (changed.Contains(name));
        }
    }
    #endregion
    #region class GridRow : vizuální řádek s daty
    /// <summary>
    /// GridRow : vizuální řádek s daty
    /// </summary>
    public class GridRow : DataGridViewRow
    {
        /// <summary>
        /// Bezparametrický konstruktor musí existovat, ale nesmí se používat.
        /// </summary>
        public GridRow()
        {
            throw new DevException("Create a instance of class GridRow without parameter (row) is not allowed.");
        }
        /// <summary>
        /// Konstruktor s převzetím reference na datový řádek
        /// </summary>
        /// <param name="row"></param>
        public GridRow(Data.Row row)
        {
            this._DataRow = row;
        }
        /// <summary>
        /// Vrací klon. Při editaci a jiných operacích se pracuje s vyklonovaným objektem, který vzniká touto metodou.
        /// Bázová metoda využívá bezparametrický konstruktor, což není v této třídě vhodná technika.
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return this.MemberwiseClone() as GridRow;
        }
        /// <summary>
        /// Data řádku
        /// </summary>
        public Data.Row DataRow { get { return this._DataRow; } }
        private Data.Row _DataRow;
        /// <summary>
        /// Data načtené tabulky
        /// </summary>
        public Data.Table DataTable { get { return (this._DataRow == null ? null : this._DataRow.Table); } }
    }
    #endregion
    #region class GridCellText : TextBox
    /// <summary>
    /// GridCellText : TextBox
    /// </summary>
    public class GridCellText : DataGridViewTextBoxCell
    {
        /// <summary>
        /// Je možno editovat?
        /// </summary>
        public bool Enabled
        {
            get { return this._Enabled; }
            set
            {
                this._Enabled = value;
                if (this.Style == null)
                    this.Style = this.InheritedStyle.Clone();
                this.Style.BackColor = (value ? this.InheritedStyle.BackColor : Color.Gray);
            }
        }
        private bool _Enabled;
        /// <summary>
        /// Při vstupu
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="throughMouseClick"></param>
        protected override void OnEnter(int rowIndex, bool throughMouseClick)
        {
            base.OnEnter(rowIndex, throughMouseClick);
            this.DataGridView.InvalidateRow(rowIndex);
        }
        /// <summary>
        /// Při opuštění
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="throughMouseClick"></param>
        protected override void OnLeave(int rowIndex, bool throughMouseClick)
        {
            base.OnLeave(rowIndex, throughMouseClick);
            this.DataGridView.InvalidateRow(rowIndex);
        }
        /// <summary>
        /// Získání hodnoty
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <returns></returns>
        protected override object GetValue(int rowIndex)
        {
            return Grid.ReadValue(this);
        }
        /// <summary>
        /// Získání formátované hodnoty
        /// </summary>
        /// <param name="value"></param>
        /// <param name="rowIndex"></param>
        /// <param name="cellStyle"></param>
        /// <param name="valueTypeConverter"></param>
        /// <param name="formattedValueTypeConverter"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
        {
            object fv = base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
            return fv;
        }
        /// <summary>
        /// Převedení formátované hodnoty do datové hodnoty
        /// </summary>
        /// <param name="formattedValue"></param>
        /// <param name="cellStyle"></param>
        /// <param name="formattedValueTypeConverter"></param>
        /// <param name="valueTypeConverter"></param>
        /// <returns></returns>
        public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
        {
            return base.ParseFormattedValue(formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
        }
        /// <summary>
        /// Vložení hodnoty
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        protected override bool SetValue(int rowIndex, object value)
        {
            return Grid.StoreValue(this, new ValueData(value));
        }
        /// <summary>
        /// Vykreslení
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="clipBounds"></param>
        /// <param name="cellBounds"></param>
        /// <param name="rowIndex"></param>
        /// <param name="cellState"></param>
        /// <param name="value"></param>
        /// <param name="formattedValue"></param>
        /// <param name="errorText"></param>
        /// <param name="cellStyle"></param>
        /// <param name="advancedBorderStyle"></param>
        /// <param name="paintParts"></param>
        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            CellJoinMode joinMode = GridPainter.ApplyCellJoinToBorders(this, rowIndex, ref formattedValue, ref advancedBorderStyle);
            GridPainter.PaintBackground(graphics, this, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, ref paintParts, joinMode);
            base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
            GridColumn column = this.OwningColumn as GridColumn;
            if (column != null && column.DataColumn.GridAsRelation)
                GridPainter.PaintRelation(graphics, this, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, ref paintParts);
        }
    }
    #endregion
    #region class GridCellCombo : ComboBox
    /// <summary>
    /// GridCellCombo : ComboBox
    /// </summary>
    public class GridCellCombo : DataGridViewComboBoxCell
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        public GridCellCombo()
        {
            this.DisplayStyleForCurrentCellOnly = true;
            this.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton;
            this.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
        }
        /// <summary>
        /// Při vstupu
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="throughMouseClick"></param>
        protected override void OnEnter(int rowIndex, bool throughMouseClick)
        {
            this._CheckLoadItems();
            base.OnEnter(rowIndex, throughMouseClick);
            this.DataGridView.InvalidateRow(rowIndex);
        }
        /// <summary>
        /// Při opuštění
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="throughMouseClick"></param>
        protected override void OnLeave(int rowIndex, bool throughMouseClick)
        {
            base.OnLeave(rowIndex, throughMouseClick);
            this.DataGridView.InvalidateRow(rowIndex);
        }
        /// <summary>
        /// Získání hodnoty
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <returns></returns>
        protected override object GetValue(int rowIndex)
        {
            this._CheckLoadItems();
            return Grid.ReadFormattedValue(this);
        }
        /// <summary>
        /// Uložení hodnoty
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        protected override bool SetValue(int rowIndex, object value)
        {
            return Grid.StoreFormattedValue(this, value);
        }
        /// <summary>
        /// Vykreslení
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="clipBounds"></param>
        /// <param name="cellBounds"></param>
        /// <param name="rowIndex"></param>
        /// <param name="cellState"></param>
        /// <param name="value"></param>
        /// <param name="formattedValue"></param>
        /// <param name="errorText"></param>
        /// <param name="cellStyle"></param>
        /// <param name="advancedBorderStyle"></param>
        /// <param name="paintParts"></param>
        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            CellJoinMode joinMode = GridPainter.ApplyCellJoinToBorders(this, rowIndex, ref formattedValue, ref advancedBorderStyle);
            GridPainter.PaintBackground(graphics, this, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, ref paintParts, joinMode);
            // advancedBorderStyle.Right = DataGridViewAdvancedCellBorderStyle.None;
            base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
        }
        /// <summary>
        /// Načtení položek editačního stylu
        /// </summary>
        private void _CheckLoadItems()
        {
            if (this._ItemsLoaded) return;

            this.Items.Clear();

            FormatStyle formatStyle = Grid.GetFormatStyle(this);
            if (formatStyle == null) return;
            //IFormatStyle formatStyle = Assistant.DataSource.GetFormatStyle(formatStyle);
            //if (formatStyle == null) return;

            IEnumerable<FormatStyleItem> items = formatStyle.EditStyleItems;
            if (items != null)
            {
                foreach (FormatStyleItem item in items)
                    this.Items.Add(item.Value);
            }

            this._ItemsLoaded = true;
        }
        private bool _ItemsLoaded;
    }
    #endregion
    #region class GridPainter : metoda pro podporu akcí v třídách Grid???Cell (formátování hodnoty, vykreslení UI), třídy a enumy
    /// <summary>
    /// GridPainter : knihovna metod pro vykreslování Gridu (formátování hodnoty, vykreslení UI)
    /// </summary>
    public static class GridPainter
    {
        /// <summary>
        /// Zajistí vykreslení pozadí pod prvkem gridu podle jeho aktuálního stavu a 
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cell"></param>
        /// <param name="clipBounds"></param>
        /// <param name="cellBounds"></param>
        /// <param name="rowIndex"></param>
        /// <param name="cellState"></param>
        /// <param name="value"></param>
        /// <param name="formattedValue"></param>
        /// <param name="errorText"></param>
        /// <param name="cellStyle"></param>
        /// <param name="advancedBorderStyle">Styl okrajů. Jde o class, nemusí se předávat jako ref.</param>
        /// <param name="paintParts">Jaké prvky se mají kreslit bázovou třídou. Jde o enum, předává se ref.</param>
        /// <param name="joinMode"></param>
        public static void PaintBackground(Graphics graphics, DataGridViewCell cell, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, ref DataGridViewPaintParts paintParts, CellJoinMode joinMode)
        {
            GridRow gridRow = cell.OwningRow as GridRow;
            GridColumn gridCol = cell.OwningColumn as GridColumn;
            if (gridRow == null || gridCol == null) return;

            Data.Row dataRow = gridRow.DataRow;
            Data.Column dataCol = gridCol.DataColumn;
            Data.Table dataTable = dataCol.Table;
            if (dataTable == null) return;

            Point activeCellCoordinate = cell.DataGridView.CurrentCellAddress;
            bool disabled = !dataTable.IsEnabled(dataRow, dataCol);
            bool hotMouse = (activeCellCoordinate.Y == rowIndex && activeCellCoordinate.X == cell.OwningColumn.Index);
            bool selectedCell = ((cellState & DataGridViewElementStates.Selected) > 0);
            bool activeRow = (cell.DataGridView.CurrentRow.Index == rowIndex);
            GridState state = GetState(disabled, hotMouse, selectedCell, activeRow);

            GridStyleItem styleItem = dataTable.GetStyle(state, dataRow, dataCol);

            Rectangle backBounds = cellBounds;
            bool joinedCell = (joinMode == CellJoinMode.SingleCell || joinMode == CellJoinMode.FirstCell || joinMode == CellJoinMode.InnerCell || joinMode == CellJoinMode.LastCell);
            using (Brush brush = styleItem.GetBrush(backBounds, joinedCell))
            {
                graphics.FillRectangle(brush, cellBounds);
            }

            paintParts = paintParts ^ DataGridViewPaintParts.Background; // ^ DataGridViewPaintParts.ContentBackground;

            cellStyle.ForeColor = styleItem.ForeColor;
            cellStyle.SelectionForeColor = styleItem.ForeColor;
        }
        /// <summary>
        /// V dané buňce vykreslí čáru, která znamená "Vztah"
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cell"></param>
        /// <param name="clipBounds"></param>
        /// <param name="cellBounds"></param>
        /// <param name="rowIndex"></param>
        /// <param name="cellState"></param>
        /// <param name="value"></param>
        /// <param name="formattedValue"></param>
        /// <param name="errorText"></param>
        /// <param name="cellStyle"></param>
        /// <param name="advancedBorderStyle"></param>
        /// <param name="paintParts"></param>
        public static void PaintRelation(Graphics graphics, DataGridViewCell cell, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, ref DataGridViewPaintParts paintParts)
        {
            Rectangle line = new Rectangle(cellBounds.X + 1, cellBounds.Bottom - 4, cellBounds.Width - 4, 2);
            using (System.Drawing.Drawing2D.LinearGradientBrush lgb = new System.Drawing.Drawing2D.LinearGradientBrush(cellBounds, Color.BlueViolet, Color.Blue, 0f))
            {
                graphics.FillRectangle(lgb, line);
            }
        }
        /// <summary>
        /// Určí režim slučování pro danou buňku ve směru Y
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="rowIndex"></param>
        /// <param name="formattedValue"></param>
        /// <param name="advancedBorderStyle"></param>
        /// <returns></returns>
        public static CellJoinMode ApplyCellJoinToBorders(DataGridViewCell cell, int rowIndex, ref object formattedValue, ref DataGridViewAdvancedBorderStyle advancedBorderStyle)
        {
            Grid grid = cell.DataGridView as Grid;
            if (grid == null) return CellJoinMode.None;
            Column column = grid.DataTable.Columns[cell.ColumnIndex];            // V tomto sloupci určujeme JoinMode
            if (!column.GridShowOnlyDifferentValues) return CellJoinMode.None;   // Nemáme toho zapotřebí

            CellJoinMode joinMode = grid.DataTable.DetectCellJoin(rowIndex, cell.ColumnIndex, Assistant.DataSource);
            switch (joinMode)
            {
                case CellJoinMode.FirstCell:
                    advancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None;
                    break;
                case CellJoinMode.LastCell:
                    formattedValue = "";
                    advancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None;
                    break;
                case CellJoinMode.InnerCell:
                    formattedValue = "";
                    advancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None;
                    advancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None;
                    break;
            }
            return joinMode;
        }
        /// <summary>
        /// Vrátí sumární stav prvku pro dané jednotkové příznaky příznaky
        /// </summary>
        /// <param name="disabled"></param>
        /// <param name="hotMouse"></param>
        /// <param name="selectedCell"></param>
        /// <param name="activeRow"></param>
        /// <returns></returns>
        public static GridState GetState(bool disabled, bool hotMouse, bool selectedCell, bool activeRow)
        {
            GridState state = (GridState)
                (disabled ? GridState.Disabled : GridState.Standard) |
                (hotMouse ? GridState.HotMouse : GridState.Standard) |
                (selectedCell ? GridState.Selected : GridState.Standard) |
                (activeRow ? GridState.ActiveRow : GridState.Standard);
            return state;
        }

    }
    #region class GridStyle, GridStyleOne, enum GridState, GridEffect
    /// <summary>
    /// GridStyle : Vizuální styl.
    /// Styl může mít tabulka, sloupec, řádek, buňka.
    /// Styl obsahuje šest jednotkových definic, pro prvek (Standard, HotMouse, ActiveRow a totéž za stavu Selected).
    /// Styl obsahuje i definici fontu.
    /// </summary>
    public class GridStyle
    {
        #region Konstrukce, instanční property
        /// <summary>
        /// Konstruktor
        /// </summary>
        public GridStyle()
        {
            this._Sets = new Dictionary<GridState, GridStyleItem>();
        }
        /// <summary>
        /// Sada stylů podle stavu prvku
        /// </summary>
        private Dictionary<GridState, GridStyleItem> _Sets;
        /// <summary>Písmo</summary>
        public Font Font { get; set; }
        /// <summary>
        /// Klon = nový objekt obsahující stejná data, ale izolovaná od svého původce.
        /// </summary>
        /// <returns></returns>
        public GridStyle Clone()
        {
            GridStyle clone = new GridStyle();
            foreach (KeyValuePair<GridState, GridStyleItem> item in this._Sets)
                clone._Sets.Add(item.Key, item.Value);
            if (this.Font != null)
                clone.Font = (Font)this.Font.Clone();
            return clone;
        }
        #endregion
        #region Indexer - čtení a zápis dat
        /// <summary>
        /// Přístup k datům stylu
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public GridStyleItem this[GridState state]
        {
            get
            {
                GridStyleItem style;
                if (this._Sets.TryGetValue(state, out style)) return style;
                return null;
            }
            set
            {
                if (this._Sets.ContainsKey(state))
                    this._Sets[state] = value;
                else
                    this._Sets.Add(state, value);
            }
        }
        #endregion
        #region Statický konstruktor defaultních stylů
        /// <summary>
        /// Obsahuje (vždy vygeneruje new) objekt popisující výchozí styl
        /// </summary>
        public static GridStyle Default
        {
            get
            {
                GridStyle result = new GridStyle();

                result[GridState.Standard] = new GridStyleItem(Color.Azure, GridEffect.Outset, 0.5f, Color.Black);
                result[GridState.HotMouse] = new GridStyleItem(Color.LavenderBlush, GridEffect.Outset, Color.Black);
                result[GridState.ActiveRow] = new GridStyleItem(Color.LightSkyBlue, GridEffect.Inset, Color.Black);
                result[GridState.ActiveRowHotMouse] = new GridStyleItem(Color.LightSkyBlue, GridEffect.Inset, Color.Black);
                result[GridState.Selected] = new GridStyleItem(Color.FromArgb(247, 247, 207), GridEffect.Inset, Color.Black);
                result[GridState.SelectedHotMouse] = new GridStyleItem(Color.BlanchedAlmond, GridEffect.Inset, Color.Black);
                result[GridState.SelectedActiveRow] = new GridStyleItem(Color.DeepSkyBlue, GridEffect.Inset, Color.White);
                result[GridState.SelectedActiveRowHotMouse] = new GridStyleItem(Color.DeepSkyBlue, GridEffect.Inset, Color.White);

                result[GridState.Disabled] = new GridStyleItem(Color.FromArgb(212, 215, 220), GridEffect.Outset, 0.3f, Color.Black);
                result[GridState.DisabledHotMouse] = new GridStyleItem(Color.LightSteelBlue, GridEffect.Outset, 0.3f, Color.Black);
                result[GridState.DisabledActiveRow] = new GridStyleItem(Color.LightSkyBlue, GridEffect.Inset, Color.Black);
                result[GridState.DisabledActiveRowHotMouse] = new GridStyleItem(Color.LightSkyBlue, GridEffect.Inset, Color.Black);
                result[GridState.DisabledSelected] = new GridStyleItem(Color.FromArgb(247, 247, 207), GridEffect.Inset, 0.6f, Color.Black);
                result[GridState.DisabledSelectedHotMouse] = new GridStyleItem(Color.LightSteelBlue, GridEffect.Inset, 0.6f, Color.Black);
                result[GridState.DisabledSelectedActiveRow] = new GridStyleItem(Color.DeepSkyBlue, GridEffect.Inset, Color.Black);
                result[GridState.DisabledSelectedActiveRowHotMouse] = new GridStyleItem(Color.DeepSkyBlue, GridEffect.Inset, Color.Black);

                result.Font = SystemFonts.DefaultFont;
                return result;
            }
        }
        #endregion
    }
    /// <summary>
    /// Definice jedné barvy pozadí + popředí + stylu
    /// </summary>
    public class GridStyleItem
    {
        #region Konstrukce, property
        /// <summary>
        /// Konstruktor položky.
        /// Dává implicitní posun barvy = 0.8f
        /// </summary>
        /// <param name="backColor"></param>
        /// <param name="effectType"></param>
        /// <param name="foreColor"></param>
        public GridStyleItem(Color backColor, GridEffect effectType, Color foreColor)
        {
            this.BackColor = backColor;
            this.EffectShiftRatio = 0.8f;
            this.EffectType = effectType;
            this.ForeColor = foreColor;
            this.UnderlineLeft = Color.MidnightBlue;
            this.UnderlineRight = Color.CornflowerBlue;
        }
        /// <summary>
        /// Konstruktor položky
        /// </summary>
        /// <param name="backColor"></param>
        /// <param name="effectType"></param>
        /// <param name="effectShiftRatio"></param>
        /// <param name="foreColor"></param>
        public GridStyleItem(Color backColor, GridEffect effectType, float effectShiftRatio, Color foreColor)
        {
            this.BackColor = backColor;
            this.EffectShiftRatio = effectShiftRatio;
            this.EffectType = effectType;
            this.ForeColor = foreColor;
            this.UnderlineLeft = Color.MidnightBlue;
            this.UnderlineRight = Color.CornflowerBlue;
        }
        /// <summary>Barva pozadí sytější (druhá barva pro styl Outset a Inset se určí posunem o EffectShift směrem k barvě White)</summary>
        public Color BackColor { get; set; }
        /// <summary>Posun doplňkové barvy pro styl Outset a Inset, směrem k barvě White. 0=žádný posun, 1.0f=čistě bílá, hodnoty mezi tím = "ColorMorphing".</summary>
        public float EffectShiftRatio { get; set; }
        /// <summary>Barevný efekt barvy pozadí</summary>
        public GridEffect EffectType { get; set; }
        /// <summary>Barva popředí</summary>
        public Color ForeColor { get; set; }
        /// <summary>Barva podtržení buňky, vlevo</summary>
        public Color UnderlineLeft { get; set; }
        /// <summary>Barva podtržení buňky, vpravo</summary>
        public Color UnderlineRight { get; set; }
        /// <summary>
        /// Klon = nový objekt obsahující stejná data, ale izolovaná od svého původce.
        /// </summary>
        /// <returns></returns>
        public GridStyleItem Clone()
        {
            return (GridStyleItem)this.MemberwiseClone();
        }
        #endregion
        #region Fyzická podpora pro vykreslování buňky
        /// <summary>
        /// Vrátí štětec pro vymalování pozadí buňky
        /// </summary>
        /// <param name="area"></param>
        /// <param name="joinedCell"></param>
        /// <returns></returns>
        public Brush GetBrush(Rectangle area, bool joinedCell)
        {
            if (this.EffectType == GridEffect.Flat)
                return new SolidBrush(this.BackColor);

            Color color1 = this.BackColor;
            Color color2 = color1.Morph(Color.White, this.EffectShiftRatio);
            float angle = (this.EffectType == GridEffect.Outset ? -90f : 90f);
            if (joinedCell)
                angle = 0f; // -90f;

            return new System.Drawing.Drawing2D.LinearGradientBrush(area, color1, color2, angle);
        }
        #endregion
    }
    /// <summary>
    /// Stav buňky z hlediska vizuálního stylu
    /// </summary>
    [Flags]
    public enum GridState
    {
        /// <summary>0: Běžný stav, bez myši, není Disabled, není Selected, není Active</summary>
        Standard = 0,
        /// <summary>1: Prvek pod myší</summary>
        HotMouse = 1,
        /// <summary>2: Prvek v aktivním řádku (kde je kurzor)</summary>
        ActiveRow = 2,
        /// <summary>3: Prvek pod myší + v aktivním řádku (kde je kurzor)</summary>
        ActiveRowHotMouse = ActiveRow | HotMouse,
        /// <summary>4: Prvek vybraný (ke kopírování)</summary>
        Selected = 4,
        /// <summary>5: Prvek pod myší + vybraný (ke kopírování)</summary>
        SelectedHotMouse = Selected | HotMouse,
        /// <summary>6: Prvek vybraný (ke kopírování) + v aktivním řádku (kde je kurzor)</summary>
        SelectedActiveRow = Selected | ActiveRow,
        /// <summary>7: Prvek pod myší + vybraný (ke kopírování) + v aktivním řádku (kde je kurzor)</summary>
        SelectedActiveRowHotMouse = Selected | ActiveRow | HotMouse,
        /// <summary>8: Prvek bez možnosti editace</summary>
        Disabled = 8,
        /// <summary>9: Prvek pod myší + bez možnosti editace</summary>
        DisabledHotMouse = Disabled | HotMouse,
        /// <summary>10: Prvek v aktivním řádku (kde je kurzor) + bez možnosti editace</summary>
        DisabledActiveRow = Disabled | ActiveRow,
        /// <summary>11: Prvek pod myší + v aktivním řádku (kde je kurzor) + bez možnosti editace</summary>
        DisabledActiveRowHotMouse = Disabled | ActiveRow | HotMouse,
        /// <summary>12: Prvek vybraný (ke kopírování) + bez možnosti editace</summary>
        DisabledSelected = Disabled | Selected,
        /// <summary>13: Prvek pod myší + vybraný (ke kopírování) + bez možnosti editace</summary>
        DisabledSelectedHotMouse = Disabled | Selected | HotMouse,
        /// <summary>14: Prvek vybraný (ke kopírování) + v aktivním řádku (kde je kurzor) + bez možnosti editace</summary>
        DisabledSelectedActiveRow = Disabled | Selected | ActiveRow,
        /// <summary>15: Prvek pod myší + vybraný (ke kopírování) + v aktivním řádku (kde je kurzor) + bez možnosti editace</summary>
        DisabledSelectedActiveRowHotMouse = Disabled | Selected | ActiveRow | HotMouse
    }
    /// <summary>
    /// Styl efektu barvy pozadí
    /// </summary>
    public enum GridEffect
    {
        /// <summary>Plochý styl, prosté vyplnění barvou BackColor</summary>
        Flat,
        /// <summary>Styl vystouplý ven = horní hrana je světlejší, dolní hrana je barvou BackColor</summary>
        Outset,
        /// <summary>Styl zamáčknutý dovnitř = horní hrana je barvou BackColor, dolní hrana je světlejší</summary>
        Inset
    }
    #endregion
    #endregion
    #region enum SimpleDataGridEditMode
    /// <summary>
    /// Možnosti editace v tabulce Grid
    /// </summary>
    public enum GridEditMode
    {
        /// <summary>
        /// Nelze editovat nic
        /// </summary>
        None,
        /// <summary>
        /// Lze editovat obsah, ale nelze přidávat / ubírat řádky
        /// </summary>
        EditContent,
        /// <summary>
        /// Lze editovat obsah, a je možno přidávat / ubírat řádky
        /// </summary>
        EditContentAndRows
    }
    #endregion
}
